/**
 * Copyright (c) 2016 Lenovo Group
 * All Rights Reserved.
 * 
 * Project Name:lmrp-base
 * Create Time: 2016年2月9日 下午11:32:56
 */
package com.lenovo.lmrp.base;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;

import org.jboss.resteasy.spi.ResteasyDeployment;

import com.google.inject.Binder;
import com.google.inject.Binding;
import com.google.inject.Module;
import com.google.inject.Singleton;
import com.google.inject.spi.LinkedKeyBinding;
import com.lenovo.sdc.framework.annotation.RestInterceptor;
import com.lenovo.sdc.framework.annotation.RestService;
import com.lenovo.sdc.framework.rest.RestServer;
import com.lenovo.sdc.framework.util.ClassScanner;

/**
 * 
 * @author wujin
 * @version v1.0
 */
public class GuiceRestServer extends RestServer {

    /**
     * @param host
     * @param port
     * @param ssl
     */
    public GuiceRestServer(String host, int port, boolean ssl) {
        super(host, port, ssl);
    }

    public Module bind(String... scanpaths) {
        return new Module() {
            @SuppressWarnings({ "unchecked", "rawtypes" })
            @Override
            public void configure(Binder binder) {
                ClassScanner scanner = new ClassScanner();

                // bind REST API implementation class
                for (String scanpath : scanpaths) {
                    List<Class<?>> classes = scanner.scanning(scanpath, false);
                    classes.forEach(clz -> {
                        if (Objects.nonNull(clz.getAnnotation(RestService.class))) {
                            /*Class[] interfaces = clz.getInterfaces();
                            if (Objects.nonNull(interfaces) && interfaces.length > 0)
                                binder.bind(interfaces[0]).to(clz).in(Singleton.class);
                            else
                                */
                            binder.bind(clz).in(Singleton.class);
                        }
                        else if (Objects.nonNull(clz.getAnnotation(RestInterceptor.class)))
                            binder.bind(clz).in(Singleton.class);
                    });
                }
            }
        };
    }

    public void deploy(String context, Collection<Binding<?>> bindings) {
        ResteasyDeployment deployment = super.deploy(context, null);

        List<Binding<?>> rootResourceBindings = new ArrayList<Binding<?>>();

        for (final Binding<?> binding : bindings) {
            Type type = null;
            if (LinkedKeyBinding.class.isInstance(binding)) {
                type = ((LinkedKeyBinding<?>)binding).getLinkedKey().getTypeLiteral().getRawType();
            }
            else {
                type = binding.getKey().getTypeLiteral().getRawType();
            }

            if (type instanceof Class) {
                final Class<?> beanClass = (Class<?>) type;
                if (beanClass.isAnnotationPresent(RestService.class)) {
                    rootResourceBindings.add(binding);
                }
                else if (beanClass.isAnnotationPresent(RestInterceptor.class)) {
                    deployment.getProviderFactory().registerProvider(beanClass);
                }
            }
        }
        for (Binding<?> binding : rootResourceBindings) {
            Class<?> beanClass;
            if (LinkedKeyBinding.class.isInstance(binding)) {
                beanClass = ((LinkedKeyBinding<?>)binding).getLinkedKey().getTypeLiteral().getRawType();
            }
            else {
                beanClass = binding.getKey().getTypeLiteral().getRawType();
            }
            deployment.getRegistry().addResourceFactory(new GuiceResourceFactory(binding.getProvider(), beanClass));
        }
    }
}
